#include "napi/native_api.h"
#include "rcim_client_adapter.h"
#include "util/Context.h"
#include "models/NativeObject.h"
#include "models/NativeBasic.h"
#include "hilog/log.h"
#include "util/Transformer.h"

using namespace rcim;

static Engine *g_engine = nullptr;

static napi_value NAPI_Global_nativeInit(napi_env env, napi_callback_info info) {
    engine_build(&g_engine);
    return nullptr;
}

void NAPI_Global_nativeSetStringListener_wrapper(const void *context, const char *value) {
    auto ts_func = rcim::context::getThreadSafeFunctionFromContext(context);
    OH_LOG_Print(LOG_APP, LOG_INFO, 1, "IM-Native", "CPP nativeSetStringListener ts_func_ptr:%{public}p value:%{public}s", &ts_func, value);
    std::vector<NativeObject *> *ret_vec = new std::vector<NativeObject *>();
    ret_vec->push_back(new NativeString(value));
    context::callArkTSListenerForAsyncMethod(context, ret_vec);
}
static napi_value NAPI_Global_nativeSetStringListener(napi_env env, napi_callback_info info) {
    if (g_engine == nullptr) {
        return nullptr;
    }
    const size_t argc_len = 1;
    size_t argc = argc_len;
    napi_value args[argc_len];
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
    
    napi_value listener_value = args[0];
    void *context = rcim::context::genContextByListener(g_engine, env, listener_value);
    engine_set_string_listener(g_engine, context, NAPI_Global_nativeSetStringListener_wrapper);
    return nullptr;
}

void NAPI_Global_nativeSetIntListener_wrapper(const void *context, long value) {
    value = value + 1000000;
    auto ts_func = rcim::context::getThreadSafeFunctionFromContext(context);
    OH_LOG_Print(LOG_APP, LOG_INFO, 1, "IM-Native", "CPP nativeSetIntListener ts_func_ptr:%{public}p value:%{public}d", &ts_func, value);
    std::vector<NativeObject *> *ret_vec = new std::vector<NativeObject *>();
    ret_vec->push_back(new NativeInt64(value));
    context::callArkTSListenerForAsyncMethod(context, ret_vec);
}
static napi_value NAPI_Global_nativeSetIntListener(napi_env env, napi_callback_info info) {
    if (g_engine == nullptr) {
        return nullptr;
    }
    const size_t argc_len = 1;
    size_t argc = argc_len;
    napi_value args[argc_len];
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
    
    napi_value listener_value = args[0];
    void *context = rcim::context::genContextByListener(g_engine, env, listener_value);
    engine_set_int_listener(g_engine, context, NAPI_Global_nativeSetIntListener_wrapper);
    return nullptr;
}
static napi_value NAPI_Global_nativeCallListeners(napi_env env, napi_callback_info info) {
    if (g_engine == nullptr) {
        return nullptr;
    }
    const size_t argc_len = 2;
    size_t argc = argc_len;
    napi_value args[argc_len];
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
    int64_t count = rcim::trans::int64FromValue(env, args[0]);
    bool need_sleep = rcim::trans::boolFromValue(env, args[1]);
    engine_call_listeners(g_engine, count, need_sleep);
    return nullptr;
}
EXTERN_C_START
static napi_value Init(napi_env env, napi_value exports) {
    napi_property_descriptor desc[] = {
        {"nativeInit", nullptr, NAPI_Global_nativeInit, nullptr, nullptr, nullptr, napi_default, nullptr},
        {"nativeSetStringListener", nullptr, NAPI_Global_nativeSetStringListener, nullptr, nullptr, nullptr,
         napi_default, nullptr},
        {"nativeSetIntListener", nullptr, NAPI_Global_nativeSetIntListener, nullptr, nullptr, nullptr, napi_default,
         nullptr},
        {"nativeCallListeners", nullptr, NAPI_Global_nativeCallListeners, nullptr, nullptr, nullptr, napi_default, nullptr }
    };
    napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
    return exports;
}
EXTERN_C_END

static napi_module demoModule = {
    .nm_version = 1,
    .nm_flags = 0,
    .nm_filename = nullptr,
    .nm_register_func = Init,
    .nm_modname = "my_lib",
    .nm_priv = ((void*)0),
    .reserved = { 0 },
};

extern "C" __attribute__((constructor)) void RegisterMy_libModule(void)
{
    napi_module_register(&demoModule);
}
